<?php

namespace oneStep\Data;

use mysql_xdevapi\Exception;

class Dbmethod
{
    /**
     * 数据库操作方法（需要优化）
     */
    private $con;
    private $sql;
    private $table;
    private $where = '';
    private $map = [];
    private $limit = '';
    private $order = '';
    private $field = '*';
    private $join = '';
    private $group = '';

    public function __construct()
    {
        $this->con = Connection::Instance();
    }

    /**
     * @param $tableName
     */
    public function table($tableName)
    {
        $this->table = $tableName;
        return $this;
    }

    /**
     * @param
     */
    public function getAll()
    {
        $str = '';
        $map = [];
        $this->compose($str, $map);
        return $this->con->getAll($str, $map);
    }

    /**
     * @param $str
     * @param $map
     */
    private function compose(&$str, &$map)
    {
        $where= $this->where? ' WHERE' . $this->where :'';
        $str       = 'SELECT  ' . $this->field . ' FROM ' . $this->table . ' ' .
            $this->join . $where . ' ' . ' ' . $this->group . ' ' . $this->order . ' ' . $this->limit;
        $map       = $this->map;
        $this->map = [];
    }

    /**
     * 获取一条
     */
    public function get()
    {
        $str = '';
        $map = [];
        $this->compose($str, $map);
        return $this->con->get($str, $map);
    }

    /**
     * @param string $field
     */
    public function field(string $field)
    {
        $this->field = $field;
    }

    /**
     * where
     * @param $where
     */
    public function where(array $where = [], $loc = 'AND')
    {
        if (is_array($where)) {
            $this->map[] = [$where[2], $this->getType($where[2])];
            $where[2]    = '?';
            $strSql      = $this->where ? '  ' . $loc : ' ';
            $this->where .= $strSql . ' ' . implode(" ", $where);
        }
        return $this;
    }

    /**
     * whereIn
     */
    public function whereIn(array $in)
    {
        foreach ($in as $key => $v) {
            $loci = $this->where ? ' AND ' : ' ';
            for ($i = 0; $i < count($v); $i++) {
                $this->map[] = [$v[$i], $this->getType($v[$i])];
                $v[$i]       = '?';
            }
            $this->where .= $loci . ' ' . $key . ' IN ' . '(' . implode(",", $v) . ')';
        }
        return $this;
    }

    /**
     * @param int $start
     * @param $limit
     */
    public function limit(...$limit)
    {
        $limit       = implode(',', $limit);
        $this->limit = 'LIMIT ' . $limit;
        return $this;
    }

    /**
     * @param $field
     * @param string $mode
     */
    public function order($field, $mode = 'ASC')
    {
        $this->order = 'ORDER BY ' . $field . ' ' . $mode;
    }

    private function getType($value)
    {
        $map = [
            'NULL'     => \PDO::PARAM_NULL,
            'integer'  => \PDO::PARAM_INT,
            'double'   => \PDO::PARAM_STR,
            'boolean'  => \PDO::PARAM_BOOL,
            'string'   => \PDO::PARAM_STR,
            'object'   => \PDO::PARAM_STR,
            'resource' => \PDO::PARAM_LOB
        ];
        return $map[gettype($value)];
    }

    /**
     * 事务
     * @param callable $actions
     */
    public function action(callable $action)
    {
        $data = ['data' => [], 'erro' => []];
        $this->con->pdo->beginTransaction();
        try {
            $data['data'] = $action($this);
            $this->con->pdo->commit();
        } catch (\Exception $e) {
            $this->con->pdo->rollBack();
            $data['erro'] = [
                'erroCode' => $e->getCode(),
                'errinfo'  => $e->getMessage()
            ];
        }
        return $data;
    }


    /**
     *
     * 添加数据
     * @param callable $actions
     */
    public function add(array $insert)
    {
        foreach ($insert as $key => &$v) {
            $this->map[] = [$v, $this->getType($v)];
            $v           = '?';
        }

        $filed     = implode(',', array_keys($insert));
        $value     = implode(',', array_values($insert));
        $str       = 'INSERT INTO ' . $this->table . ' ' . '(' . $filed . ')' . ' VALUES ' . '(' . "$value" . ')';
        $map       = $this->map;
        $this->map = [];
        return $this->con->exec($str, $map);
    }

    /**
     * 更新数据
     */
    public function update(array $saveData)
    {
        $set = '';
        $i   = 0;
        foreach ($saveData as $key => $v) {
            $i++;
            $f     = $i == count($saveData) ? ' ' : ' , ';
            $set   .= $key . ' =? ' . $f;
            $map[] = [$v, $this->getType($v)];
        }
        $map       = array_merge($map, $this->map);
        $this->map = [];
        $str       = "update " . $this->table . " set $set " . 'WHERE ' . $this->where;
        return $this->con->exec($str, $map);
    }

    /**
     * join
     */
    public function join(string $on)
    {
        $this->join = 'LEFT JOIN ' . $on;
        return $this;
    }

    /**
     * 分组
     */
    public function group(string $filed)
    {
        $this->group = ' GROUP BY ' . $filed;
        return $this;
    }


    /**
     * 原生查询
     * @param $sql
     * @return mixed
     */
    public function query($sql)
    {
        return $this->con->query($sql);
    }

    /**
     * @param $sql
     * @return mixed
     */
    public function quote($sql)
    {
        return $this->con->quote($sql);
    }

    /**
     * @return mixed
     */
    public function errorCode()
    {
        return $this->con->errorCode;
    }

    /**
     * @return mixed
     */
    public function errorInfo()
    {
        return $this->con->errorInfo;
    }

}
